package org.topteam.dao;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Example;
import org.hibernate.transform.Transformers;

import java.io.Serializable;
import java.util.List;

/**
 * @author Jiang feng
 */
public class BaseDao {

    private SessionFactory sf;

    /**
     * @param sf
     */
    public BaseDao(SessionFactory sf) {
        this.sf = sf;
    }

    protected Session getSession() {
        return sf.getCurrentSession();
    }


    @SuppressWarnings("unchecked")
    public <T> T findById(Class<T> cls, Serializable id) throws Exception {
        return (T) this.getSession().get(cls, id);
    }

    public <T> T save(T t) throws Exception {
        this.getSession().save(t);
        return t;
    }

    public <T> void update(T t) throws Exception {
        this.getSession().update(t);
    }

    @SuppressWarnings("unchecked")
    public <T> T merge(T t) throws Exception {
        return (T) this.getSession().merge(t);
    }

    public <T> void saveOrUpdate(T t) throws Exception {
        this.getSession().saveOrUpdate(t);
    }

    public <T> void delete(T t) throws Exception {
        this.getSession().delete(t);
    }

    public <T> void deleteById(Class<T> cls, Serializable id) throws Exception {
        Object t = this.getSession().load(cls, id);
        if (t != null)
            this.getSession().delete(t);
    }

    protected int execUpdateHQL(String queryString) throws Exception {
        return execUpdateHQL(queryString, (Object[]) null);
    }

    protected int execUpdateHQL(String queryString, final Object... values) throws Exception {
        Query q = this.getSession().createQuery(queryString);
        if (values != null) {
            for (int i = 0; i < values.length; i++) {
                q.setParameter(i, values[i]);
            }
        }
        return q.executeUpdate();
    }

    protected <T> List<T> findByHQL(String queryString) throws Exception {
        return findByHQL(queryString, (Object[]) null);
    }

    @SuppressWarnings("unchecked")
    protected <T> List<T> findByHQL(String queryString, final Object... values) throws Exception {
        Query q = this.getSession().createQuery(queryString);
        if (values != null) {
            for (int i = 0; i < values.length; i++) {
                q.setParameter(i, values[i]);
            }
        }
        return q.list();
    }

    protected <T> List<T> findPageByHQL(String queryString, int page, int pageSize) throws Exception {
        return findPageByHQL(queryString, page, pageSize, (Object[]) null);
    }

    @SuppressWarnings("unchecked")
    protected <T> List<T> findPageByHQL(String queryString, int page, int pageSize, final Object... values) throws Exception {
        Query q = this.getSession().createQuery(queryString);
        if (values != null) {
            for (int i = 0; i < values.length; i++) {
                q.setParameter(i, values[i]);
            }
        }
        q.setFirstResult((page - 1) * pageSize).setMaxResults(pageSize);
        return q.list();
    }

    protected <T> List<T> findPageBySQL(String queryString, int page, int pageSize, Class<T> cls, final Object... values) throws Exception {
        Query q = this.getSession().createSQLQuery(queryString).addEntity(cls);
        if (values != null) {
            for (int i = 0; i < values.length; i++) {
                q.setParameter(i, values[i]);
            }
        }
        q.setFirstResult((page - 1) * pageSize).setMaxResults(pageSize);
        return q.list();
    }

    protected <T> List<T> findPageByQuery(Query q, int page, int pageSize) throws Exception {
        q.setFirstResult((page - 1) * pageSize).setMaxResults(pageSize);
        return q.list();
    }

    protected long findCountByHQL(String queryString) throws Exception {
        return findCountByHQL(queryString, (Object[]) null);
    }

    protected long findCountByHQL(String queryString, final Object... values) throws Exception {
        Query q = this.getSession().createQuery(queryString);
        if (values != null) {
            for (int i = 0; i < values.length; i++) {
                q.setParameter(i, values[i]);
            }
        }
        return count(q);
    }

    protected long findCountBySQL(String queryString, final Object... values) throws Exception {
        Query q = this.getSession().createSQLQuery(queryString);
        if (values != null) {
            for (int i = 0; i < values.length; i++) {
                q.setParameter(i, values[i]);
            }
        }
        return count(q);
    }

    @SuppressWarnings("unchecked")
    protected <T> T findUniqueByHQL(String queryString, final Object... values) throws Exception {
        Query q = this.getSession().createQuery(queryString);
        if (values != null) {
            for (int i = 0; i < values.length; i++) {
                q.setParameter(i, values[i]);
            }
        }
        return (T) q.uniqueResult();
    }

    protected Object findUniqueBySQL(String sql) throws Exception {
        return findUniqueBySQL(sql, (Object[]) null);
    }

    protected Object findUniqueBySQL(String sql, final Object... values) throws Exception {
        Query q = this.getSession().createSQLQuery(sql);
        if (values != null) {
            for (int i = 0; i < values.length; i++) {
                q.setParameter(i, values[i]);
            }
        }
        return q.uniqueResult();
    }

    protected <T> T findFirstByHQL(String queryString, final Object... values) throws Exception {
        Query q = this.getSession().createQuery(queryString);
        if (values != null) {
            for (int i = 0; i < values.length; i++) {
                q.setParameter(i, values[i]);
            }
        }
        q.setMaxResults(1);
        return (T) q.uniqueResult();
    }

    protected int execUpdateSQL(String queryString) throws Exception {
        return execUpdateSQL(queryString, (Object[]) null);
    }

    protected int execUpdateSQL(String queryString, final Object... values) throws Exception {
        Query q = this.getSession().createSQLQuery(queryString);
        if (values != null) {
            for (int i = 0; i < values.length; i++) {
                q.setParameter(i, values[i]);
            }
        }
        return q.executeUpdate();
    }

    protected <T> List<T> findBySQL(String queryString) throws Exception {
        return findBySQL(queryString, (Object[]) null);
    }

    @SuppressWarnings("unchecked")
    protected <T> List<T> findBySQL(String queryString, final Object... values) throws Exception {
        Query q = this.getSession().createSQLQuery(queryString);
        if (values != null) {
            for (int i = 0; i < values.length; i++) {
                q.setParameter(i, values[i]);
            }
        }
        return q.list();
    }

    @SuppressWarnings("unchecked")
    protected <T> List<T> findMapBySQL(String queryString, final Object... values) throws Exception {
        Query q = this.getSession().createSQLQuery(queryString);
        if (values != null) {
            for (int i = 0; i < values.length; i++) {
                q.setParameter(i, values[i]);
            }
        }
        q.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
        return q.list();
    }

    protected <T> List<T> findBySQL(String queryString, Class<T> t) throws Exception {
        return findByHQL(queryString, (Object[]) null);
    }

    @SuppressWarnings("unchecked")
    protected <T> List<T> findBySQL(String queryString, Class<T> t, final Object... values) throws Exception {
        Query q = this.getSession().createSQLQuery(queryString).addEntity(t);
        if (values != null) {
            for (int i = 0; i < values.length; i++) {
                q.setParameter(i, values[i]);
            }
        }
        return q.list();
    }

    protected long count(Query q) throws Exception {
        return Long.valueOf(q.uniqueResult().toString());
    }

    public <T> List<T> findAll(Class<T> cls) throws Exception {
        return this.getSession().createCriteria(cls).list();
    }

    public <T> List<T> findByExample(T t) throws Exception {
        Example example = Example.create(t);
        return getSession().createCriteria(t.getClass()).add(example).list();
    }
}
